#include <text.h>
#include <std.h>
#include <pio.h>
#include <error.h>

#define PALETTE_COLOR_NUMBER 0x3c8
#define PALETTE_RED          0x3c9
#define PALETTE_GREEN        0x3c9
#define PALETTE_BLUE         0x3c9

#define INDENT 24

static unsigned char textcolor=7;
static unsigned short screen_end=2000;
static unsigned char *vgafb=(unsigned char *)0xb8000;
static unsigned short crtcio=0x3d4;

static unsigned short cursor=0;

int init_video()
{
	if((inb(VGA_MISC_READ) & 0x01) != 0)
	{
		vgafb = (unsigned char *)0xB8000L;
		crtcio = 0x3D4;
	}
	else
	{
		vgafb = (unsigned char *)0xB0000L;
		crtcio = 0x3B4;
	}
	screen_end= (*(unsigned short *)0x44A)* (*(unsigned char *)0x484 + 1)-80;	
	setpalette(0,0,0,0); 
	outb(crtcio, 15);
	cursor|=inb(crtcio+1);
 	outb(crtcio, 14);
 	cursor|=(inb(crtcio+1)<<8);
 	
 	/*Ask the actual cursor to get lost somewhere outside*/
 	
 	outb(crtcio, 15);
	outb(crtcio+1,100);
 	outb(crtcio, 14);
 	outb(crtcio+1,100);
 	printf("\nOn text screen-%x",vgafb);
	return SUCCESS;
}

unsigned short getcursor(void)
{
	return cursor;
}

void setcursor(unsigned short offset)
{
	cursor=offset;
}

int clrscr()
{
  unsigned char *vidmem = (unsigned char *)vgafb;
  const long size = 80*25;
  long loop;
  for (loop=0; loop<size; loop++) {
    *vidmem++ = 0;
    *vidmem++ = textcolor;
  }
  setcursor(0);
  return SUCCESS;
}

int scroll_screen(void)
{
	char ch,col;
	unsigned short offset=0;
	unsigned char *vidmem=(unsigned char *)vgafb;
	while(offset<(screen_end))	{
		ch=*(vidmem+offset*2);
		col=*(vidmem+offset*2+1);
		*(vidmem+offset*2-160)=ch;
		*(vidmem+offset*2-160+1)=col;
		offset++;
	}
	while(offset<(screen_end+160))	{
		*(vidmem+offset*2-160)=0;
		*(vidmem+offset*2-160+1)=7;
		offset++;
	}
	setcursor(getcursor()-80);
	return SUCCESS;
}

void skipline(int nol)
{
	unsigned short offset;
	unsigned short cmpof=0;
	offset=getcursor();
	while(cmpof<screen_end)
	{
		if(offset>=cmpof && offset<(cmpof+80))
		{
			offset=cmpof+80;
			break;
		}
		cmpof=cmpof+80;
	}
	nol--;
	while(nol!=0)
	{
		offset+=80;
		nol--;
	}
	setcursor(offset);
	if(offset>=screen_end)
	{
		scroll_screen();
	}
}

/*tab(1,8)
offset=88
y=80
x=8
res=8
*/

void tab(char count,unsigned char tabcount)
{
	unsigned int offset,x,y,res;
	offset=getcursor();
	y=80*(offset/80);
	x=offset-y;
	res=tabcount;
	while(x>=res)	{
		res+=tabcount;
	}
	y+=res;
	count--;
	while(--count>0)	{
		y+=tabcount;
	}
	setcursor(y);
}
	
void settextcolor(unsigned char color)
{
	textcolor=color;
}

static void (*putch)(int);
void setputchar(void (*put_fn)(int))
{
	putch=put_fn;
}

int putchar(int ch)
{
		unsigned short offset;
		unsigned char *vidmem=(unsigned char *)vgafb;
		if(putch!=NULL)	{
			putch(ch);
			return;
		}
		offset=getcursor();
		if(ch=='\n')	{
			skipline(1);
		} else if(ch=='\t')	{
			tab(1,INDENT);
		} else	{
			vidmem += offset*2;
 	 		*vidmem=(unsigned char)ch;
 	 		*(vidmem+1)=textcolor;
 	 		offset++;
 	 		setcursor(offset);
 	 	}
		if(offset>=screen_end)	{
			scroll_screen();
		}
		return SUCCESS;
}

int putc(unsigned char ch,unsigned char color)
{
	unsigned short offset;
	unsigned char *vidmem=(unsigned char *)vgafb;
	offset=getcursor();
	vidmem += offset*2;
 	*vidmem=(unsigned char)ch;
	*(vidmem+1)=textcolor;
 	offset++;
 	setcursor(offset);
	return SUCCESS;
}

int setpalette(unsigned char color,unsigned char r,unsigned char g,unsigned char b)
{
	outb(PALETTE_COLOR_NUMBER,color);
	outb(PALETTE_RED,r);
	outb(PALETTE_GREEN,g);
	outb(PALETTE_BLUE,b);
	return SUCCESS;
}

void movecursor(char amt)
{
	unsigned short offset;
	unsigned char *vidmem=(unsigned char *)vgafb;
	offset=getcursor();
	offset+=amt;
	setcursor(offset);
}

/*Text mode menu driven interface
Call init_opt passing number of options
Add all options using add_opt
Get user's selection using getopt 
*/

static unsigned short glob_menuc=0;
static unsigned short glob_menustart=0;


void init_opt(char noopt)
{
	unsigned short c;
	c=(getcursor()/80)+noopt;
	while(c>=23)	{
		scroll_screen();
		c=(getcursor()/80)+noopt;
	}
	glob_menuc=glob_menustart=c;		
}

void addopt(char noopt,char *opts)
{
	init_opt(noopt);
	setcursor(glob_menuc*80);
	printf(opts);
	glob_menuc+=noopt;
}

#define HL_COLOR 0xf0
#define TXT_COLOR 7

void lum(unsigned short optno)
{
	int i=0;
	unsigned char *vid=(unsigned char *)0xb8000;
	optno*=80;
	vid+=optno*2+1;
	if(*vid<=15)
	{
		while(*(vid+i-1)!=0 || i<50)
		{
			*(vid+i)=HL_COLOR;
			i+=2;		
		}
	}
	else
	{
		while(*(vid+i-1)!=0 || i<50)
		{
			*(vid+i)=TXT_COLOR;
			i+=2;		
		}
	}
}

char getopt()
{
	int c;
	char opt;
	opt=glob_menustart;
	lum(opt);
	while(1)
	{
		c=waitkey();
		switch(c)
		{
			case 0x0a:setcursor(glob_menuc*80+80);
			return opt-glob_menustart;
			break;
			case 0x97:if(opt>glob_menustart)
			{
				lum(opt);
				opt--;
				lum(opt);
			}
			else
			{
				lum(opt);
				opt=glob_menuc-1;
				lum(opt);
			}
			break;
			case 0x98:if(opt<(glob_menuc-1))
			{
				lum(opt);
				opt++;
				lum(opt);
			}
			else
			{
				lum(opt);
				opt=glob_menustart;
				lum(opt);
			}
		}
	}
	printf("\n\n");
}

